package org.agile4j.rpc.client;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.agile4j.rpc.client.bean.RpcRequest;
import org.agile4j.rpc.client.bean.RpcResponse;
import org.agile4j.rpc.client.codec.RpcEncoder;
import org.agile4j.rpc.client.codec.RpcDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *  RPC 客户端，只需扩展 Netty 提供的SimpleChannelInboundHandler抽象类
 *  
 * @author Administrator
 */
public class RpcClient extends SimpleChannelInboundHandler<RpcResponse>{
	
	private static final Logger LOGGER = LoggerFactory.getLogger(RpcClient.class) ;

	private String host ;
	private int port ;
	
	private RpcResponse response ;
	
	public RpcClient(String host, int port) {
		this.host = host;
		this.port = port;
	}

	@Override
	protected void channelRead0(ChannelHandlerContext ctx, RpcResponse response) throws Exception {
		this.response = response ;
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
		LOGGER.error("client caught exception",cause);
		ctx.close();
	}
	
	public RpcResponse send(RpcRequest request) throws Exception{
		EventLoopGroup group = new NioEventLoopGroup();
		try {
			Bootstrap bootstrap = new Bootstrap() ;
			bootstrap.group(group).channel(NioSocketChannel.class)
				.handler(new ChannelInitializer<SocketChannel>() {
					@Override
					public void initChannel(SocketChannel channel) throws Exception {
						ChannelPipeline pipeline = channel.pipeline();
						pipeline.addLast(new RpcEncoder(RpcRequest.class));  // 将 RPC 请求进行编码（为了发送请求）
						pipeline.addLast(new RpcDecoder(RpcResponse.class));	// 将 RPC 响应进行解码（为了处理响应）
						pipeline.addLast(RpcClient.this); // 使用 RpcClient 发送 RPC 请求
					}
				});
			bootstrap.option(ChannelOption.SO_KEEPALIVE, true) ;
			// 连接 RPC 服务器
			ChannelFuture future = bootstrap.connect(host, port).sync();
			// 写入 RPC 请求数据并关闭连接
			Channel channel = future.channel() ;
			channel.writeAndFlush(request).sync() ;
			channel.closeFuture().sync() ;
			// 返回 RPC 响应对象
			return response;
		} finally {
			group.shutdownGracefully() ;
		}
	}
}
